--wuqibo
--2021.8.10
--拉霸抽奖驱动类
--[[
  使用方法:
    --实例化
    self.turntable = TurntableDriverLine:new(cellPrefab, 5, mask.sizeDelta.y)
    --注册每次Cell刷新的回调，类似TableView插件
    self.turntable:setUpdateCallback(
        function(cell, isInit)
            if not isInit then
                //播放跳动音效
            end
            cell.trans:Find("Text"):GetComponent("Text").text = cell.index
        end
    )
    --开始滚动
    self.turntable:start(stopIndex, function(resultCell)
            Log(resultCell.trans.name)
        end
    )
    ● 立即停止
    self.turntable:stop()
    ● 对外只读方法：
    bool isRunning = self.turntable:isRunning()
]]

GameObject = UnityEngine.GameObject
DOVirtual = DG.Tweening.DOVirtual

local TurntableDriverLine = fb_class("TurntableDriverLine")

--cellPrefab：元素预置体
--total：元素总数量
--maskHeight：Mask窗口高度
--space：间距（默认0）
--roundCount: 滚动的总圈数，必须是整数，不传默认5
--duration：滚动时间(秒)，不传默认4
function TurntableDriverLine:ctor(cellPrefab, total, maskHeight, space, roundCount, duration)
    self.cellPrefab = cellPrefab
    self.total = total
    self.maskHeight = maskHeight
    self.space = space or 0
    self.roundCount = roundCount or 5
    self.duration = duration or 4

    self.cellHeight = self.cellPrefab.sizeDelta.y

    self.cellPrefab.gameObject:SetActive(false)
    local spawnCount = math.ceil(maskHeight / (self.cellHeight + self.space)) + 1
    self.cells = {}
    self.cells2 = {}
    for i = 1, spawnCount do
        local cell = {}
        cell.trans = GameObject.Instantiate(self.cellPrefab)
        cell.trans:SetParent(self.cellPrefab.parent, false)
        cell.trans.gameObject:SetActive(true)
        self.cells[i] = cell
        self.cells2[i] = cell
    end
    return self
end

function TurntableDriverLine:_getBottomCell()
    local bottomCell = self.cells[1]
    local minY = bottomCell.trans.anchoredPosition.y
    for i = 1, self.cellsCount do
        local cell = self.cells[i]
        if cell.trans.anchoredPosition.y < minY then
            minY = cell.trans.anchoredPosition.y
            bottomCell = cell
        end
    end
    return bottomCell
end

function TurntableDriverLine:_getOverCenterFirstCell()
    for i = 1, self.cellsCount do
        local cell = self.cells2[i]
        if cell.trans.anchoredPosition.y >= 0 then
            return cell
        end
    end
    return nil
end

function TurntableDriverLine:_getTopCellIndex()
    local topCell = self.cells[1]
    local maxY = topCell.trans.anchoredPosition.y
    for i = 1, self.cellsCount do
        local cell = self.cells[i]
        if cell.trans.anchoredPosition.y > maxY then
            maxY = cell.trans.anchoredPosition.y
            topCell = cell
        end
    end
    return topCell.index
end

function TurntableDriverLine:_sortCells()
    table.sort(
        self.cells2,
        function(a, b)
            return a.trans.anchoredPosition.y < b.trans.anchoredPosition.y
        end
    )
end

function TurntableDriverLine:setUpdateCallback(setCellFunctin)
    self.setCellFunctin = setCellFunctin
    self:initPos()
    return self
end

function TurntableDriverLine:initPos()
    self.cellsCount = #self.cells
    for i = 1, self.cellsCount do
        local index = self.cellsCount - i + 1
        local cell = self.cells[index]
        cell.index = index
        local y = self.maskHeight * 0.5 - self.space - self.cellHeight * 0.5 - (i - 1) * (self.cellHeight + self.space)
        cell.trans.anchoredPosition = Vector2(0, y)
        while cell.index > self.total do
            cell.index = cell.index - self.total
        end
        if self.setCellFunctin then
            self.setCellFunctin(cell, true)
        end
    end
end

function TurntableDriverLine:start(stopIndex, onStop, selfObject)
    if stopIndex < 1 or stopIndex > self.total then
        LogError("stopIndex不在范围")
        return
    end

    if self._isRunning then
        return
    end

    self.onStop = onStop
    self.selfObject = selfObject

    --初始化
    local bottomCell = self:_getBottomCell()
    local bottomCellY = bottomCell.trans.anchoredPosition.y
    self:_sortCells()
    for i = 1, self.cellsCount do
        local cell = self.cells2[i]
        cell.offsetY = bottomCellY + (i - 1) * (self.cellHeight + self.space)
        cell._offsetIndex = 0
    end
    
    self.fromY = 0
    self.toY = 0
    for i = 1, self.roundCount do
        local oneRoundDis = (self.cellHeight + self.space) * self.total
        self.toY = self.toY - oneRoundDis
    end
    
    local centerCell = self:_getOverCenterFirstCell()
    local index = centerCell.index
    local offfsetY = centerCell.trans.anchoredPosition.y
    for i = 1, self.total do
        if index == stopIndex then
            self.toY = self.toY - offfsetY
            break
        else
            offfsetY = offfsetY + self.cellHeight + self.space
            index = index + 1
            if index > self.total then
                index = 1
            end
        end
    end
    
    --开始移动
    self.topCellIndex = self:_getTopCellIndex()
    local allCellsHeight = (self.cellHeight + self.space) * self.cellsCount
    self.resultCell = nil
    self._isRunning = true
    DOVirtual.Float(
        self.fromY,
        self.toY,
        self.duration,
        function(value)
            for i = 1, self.cellsCount do
                local cell = self.cells2[i]
                local y = value + cell.offsetY
                if y < -self.maskHeight * 0.5 - self.cellHeight then
                    cell.offsetY = cell.offsetY + allCellsHeight
                    y = value + cell.offsetY
                    self.topCellIndex = self.topCellIndex + 1
                    if self.topCellIndex > self.total then
                        self.topCellIndex = 1
                    end
                    cell.index = self.topCellIndex
                    if self.setCellFunctin then
                        self.setCellFunctin(cell, false)
                    end
                end
                cell.trans.anchoredPosition = Vector2(0, y)
            end
        end
    ):SetEase(Ease.OutSine):OnKill(
        function()
            self._isRunning = false
            local resultCell = self:getCellByIndex(stopIndex)
            if self.selfObject then
                self.onStop(self.selfObject, resultCell)
            else
                self.onStop(resultCell)
            end
        end
    )
end

function TurntableDriverLine:stop()
    if self.updateHandler then
        UpdateBeat:RemoveListener(self.updateHandler)
        self.updateHandler = nil
    end
    self._isRunning = false
end

--根据索引获取cell，如果目标cell在Mask外部不可见将返回nil
function TurntableDriverLine:getCellByIndex(index)
    for i = 1, self.cellsCount do
        local cell = self.cells[i]
        local y = cell.trans.anchoredPosition.y
        local top = self.maskHeight * 0.5
        local bottom = -self.maskHeight * 0.5
        if cell.index == index and y < top and y > bottom then
            return cell
        end
    end
    return nil
end

--对外函数：判断转盘是否在正式抽奖转动中
function TurntableDriverLine:isRunning()
    return self._isRunning
end

--对外函数：销毁
function TurntableDriverLine:destroy()
    if self.cells then
        for key, cell in pairs(self.cells) do
            GameObject.Destroy(cell.trans.gameObject)
        end
    end
    fb_clear(self)
end

return TurntableDriverLine
